﻿using System;
using System.Data;
using System.Data.Objects;
using System.Linq;
using log4net;

namespace EntityFrameworkExtension
{
    public class SaveChangesHandler
    {
        private enum ColumnName
        {
            LastModifiedOn
        }

        private readonly ILog logger = LogManager.GetLogger(typeof(SaveChangesHandler));

        public void HeimdallEntitySavingChanges(object sender, EventArgs e)
        {
            var context = sender as ObjectContext;
            if (context != null)
            {
                ResetFalseModified(context);

                SetLastModifiedOn(context);
            }
        }

        private void SetLastModifiedOn(ObjectContext context)
        {
            var dateTime = DateTime.Now;

            foreach (var entry in context.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified))
            {
                if (entry.Entity == null)
                {
                    logger.DebugFormat("entity {0} is being reset to unchanged", entry.EntitySet.Name);
                    continue; // highly unlikely?
                }

                var property = entry.Entity.GetType().GetProperty(ColumnName.LastModifiedOn.ToString());
                if (property != null && property.CanWrite)
                    property.SetValue(entry.Entity, dateTime, null);
            }
        }

        private void ResetFalseModified(ObjectContext context)
        {
            foreach (var entry in from entry in context.ObjectStateManager.GetObjectStateEntries(EntityState.Modified)
                                  where entry.Entity != null
                                  let current = entry.CurrentValues
                                  let original = entry.OriginalValues
                                  let hasChanges = entry.GetModifiedProperties().Where(y => y != ColumnName.LastModifiedOn.ToString()).Any(x => !current[x].Equals(original[x]))
                                  where !hasChanges
                                  select entry)
            {
                logger.DebugFormat("entity {0} is being reset to unchanged", entry.EntitySet.Name);
                entry.ChangeState(EntityState.Unchanged);
            }
        }
    }
}
